#pragma once

#include "noncopyable.h"
#include "Timestamp.h"

#include <functional>
#include <memory>

class EventLoop;

/**
 * 理清 EventLoop、Poller、Channel之间的关系 ← Reactor模型上对应多路事件分发器Demultiplex
 * Channel 理解为通道，封装了sockfd和感兴趣的event，如EPOLLIN、EPOLLOUT事件
 * 还绑定了poller返回的具体事件
*/
class Channel : noncopyable
{
public:
    using EventCallback = std::function<void()>;  // 事件的回调
    using ReadEventCallback = std::function<void(Timestamp)>;  // 可读事件的回调

    Channel(EventLoop* loop, int fd);
    ~Channel();

    // fd得到poller通知以后，处理事件，调用相应的回调方法处理事件
    void handleEvent(Timestamp receiveTime);
    
    // 设置回调函数对象
    // 设置可读回调
    void setReadCallback(ReadEventCallback cb) { readCallback_ = std::move(cb); }
    // 设置可写回调
    void setWriteCallback(EventCallback cb) { writeCallback_ = std::move(cb); }
    // 设置关闭回调
    void setCloseCallback(EventCallback cb) { closeCallback_ = std::move(cb); }
    // 设置错误回调
    void setErrorCallback(EventCallback cb) { errorCallback_ = std::move(cb); }

    // 防止当channel被手动remove掉，channel还在执行回调操作
    void tie(const std::shared_ptr<void>&);

    // 返回当前channel是哪个fd的管家
    int fd() const { return fd_; }

    // 返回前channel对应的fd感兴趣的事件
    int events() const { return events_; }

    // 给pollers用的，poller(epoll)在监听事件，监听到了就设置事件
    void set_revents(int revt) { revents_ = revt; }

    // 设置fd相应的事件状态
    // 对读事件感兴趣
    void enableReading() { events_ |= kReadEvent; update();  /*update调用epoll_ctl*/ }
    // 对读事件不感兴趣
    void disableReading() { events_ &= ~kReadEvent; update(); }
    // 对写事件感兴趣
    void enableWriting() { events_ |= kWriteEvent; update(); }
    // 对写事件不感兴趣
    void disableWriting() { events_ &= ~kWriteEvent; update(); }
    // 对任何事件不感兴趣
    void disableAll() { events_ = kNoneEvent; update(); }

    // 返回fd当前感兴趣事件的状态
    // 是否对任何事件不感兴趣
    bool isNoneEvent() const { return events_ == kNoneEvent; }
    // 是否对读事件感兴趣
    bool isReading() const { return events_ == kReadEvent; }
    // 是否对写事件感兴趣
    bool isWriting() const { return events_ == kWriteEvent; }

    // for poller
    int index() const { return index_; }
    void setIndex(int idx) { index_ = idx; }

    // 当前channel属于哪个eventloop
    EventLoop* ownerLoop() {return loop_; }

    // 删除channel
    void remove();
private:
    // fd的状态
    static const int kNoneEvent;  // 对没有任何事件感兴趣
    static const int kReadEvent;  // 对读事件感兴趣
    static const int kWriteEvent;  // 对写事件感兴趣

    EventLoop *loop_;  // 事件循环（fd属于哪个EventLoop对象）
    const int fd_;  // fd，poller监听的对象
    int events_;  // fd感兴趣的事件
    int revents_;  // poller返回的具体发生的事件
    int index_;  // 表示channel在poller中的状态（未添加、已添加、已删除）

    std::weak_ptr<void> tie_;
    bool tied_;

    // 因为channel通道里能够获知fd最终发生的具体的事件events，所以它负责调用具体事件的回调操作
    // 这些回调用户给channel
    ReadEventCallback readCallback_;  // 可读回调
    EventCallback writeCallback_;  // 可写回调
    EventCallback closeCallback_;  // 关闭回调
    EventCallback errorCallback_;  // 错误回调

    void update();

    // 受保护的处理事件
    void handleEventWithGuard(Timestamp receiveTime);
};